// 1. 通过{}创建对象
// let obj = {}


// 2. new Object()
// let obj = new Object()


// 3. 使用字面量创建对象
let obj = {name:'csc', age:18}


// 4. 使用工厂模式创建对象
// 定义一个工厂方法
function createObj(name) {
    var obj = new Object()
    obj.name = name
    obj.sayName = function () {
        console.log(this.name);
    }
    return obj
}
// 优点：解决了前面的代码冗余问题
// 缺点：调用的还是不同的方法


/**
 *  5. 构造函数模式创建对象
 **/
function Person(name) {
    this.name = name
    this.sayName = function () {
        console.log(this.name);
    }
}

var p1 = new Person('zhang');
var p2 = new Person('li');
console.log(p1.sayName == p2.sayName); // false
// 没有解决方法不能共享的问题


/**
 *  6. 通过原型模式创建对象
 **/
// 一、
// function Animal() {
//     Animal.prototype.name = 'animal'
//     Animal.prototype.sayName = function () {
//         console.log(this.name);
//     }
// }
// 方法是共享的

// 二、
// 如果往新建的对象中加入属性，那么这个属性是放在对象中，如果存在与原型同名的属性，也不会改变原型的值。但是访问这个属性，拿到的是对象的值。
function Animal(name) {
    Animal.prototype.name = name
    Animal.prototype.sayName = function () {
        console.log(this.name);
    }
}
var p1 = new Person('zhang');
var p2 = new Person('li');
p1.name = 'dog'
console.log(p1.name);// dog
console.log(p2.name); // li

// 三、
// 假如原型中包含有引用类型的属性，那么如果某个对象修改了该属性的值，所有的该原型创建的对象访问的值都会改变。
function Animal() {}
Animal.prototype = {
    name: 'animal',
    fruit: ['apple', 'pink'],
    sayName: function () {
        console.log(this.name);
    }
}
var a1 = new Animal();
var a2 = new Animal();
a2.fruit.push('snake');
console.log(a2.fruit);
console.log(a1.fruit);


/**
 *  7. 通过原型+构造函数的方式构建对象
 **/
//  这种方式结合了上面两种方式，解决了代码冗余，方法不能共享，引用类型改变值的问题。
function Animal(name) {
    this.name = name
    this.friends = ['dog', 'cat']
}
Animal.prototype.sayName = function () {
    console.log(this.name);
}
var a1 = new Animal('d');
var a2 = new Animal('c');
a1.friends.push('tiger')
a1.sayName()
a2.sayName()
console.log(a1.friends);
console.log(a2.friends);